commonlibsse_ng\re\n/
NiSmartPointer.rs

1use core::fmt;
2use std::cmp::Eq;
3use std::hash::{Hash, Hasher};
4use std::marker::PhantomData;
5use std::ptr::NonNull;
6
7pub trait RefCountable {
8    /// Increment ref count
9    fn inc_ref_count(&self);
10    /// Decrement ref count
11    fn dec_ref_count(&mut self);
12}
13
14pub struct NiPointer<T: RefCountable> {
15    ptr: Option<NonNull<T>>,
16    _marker: PhantomData<T>,
17}
18
19impl<T: RefCountable> fmt::Debug for NiPointer<T> {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        f.debug_struct("NiPointer").field("ptr", &self.ptr).field("_marker", &self._marker).finish()
22    }
23}
24
25impl<T: RefCountable> Default for NiPointer<T> {
26    #[inline]
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl<T: RefCountable> NiPointer<T> {
33    #[inline]
34    pub const fn new() -> Self {
35        Self { ptr: None, _marker: PhantomData }
36    }
37
38    #[inline]
39    pub fn from_raw(ptr: *mut T) -> Self {
40        let ni_pointer = Self { ptr: NonNull::new(ptr), _marker: PhantomData };
41        ni_pointer.try_attach();
42        ni_pointer
43    }
44
45    fn try_attach(&self) {
46        if let Some(ref_ptr) = self.ptr {
47            unsafe { ref_ptr.as_ref().inc_ref_count() };
48        }
49    }
50
51    fn try_detach(&mut self) {
52        if let Some(mut ptr) = self.ptr.take() {
53            unsafe { ptr.as_mut().dec_ref_count() };
54        }
55    }
56
57    #[inline]
58    pub fn reset(&mut self) {
59        self.try_detach();
60    }
61
62    #[inline]
63    pub const fn is_null(&self) -> bool {
64        self.ptr.is_none()
65    }
66
67    #[inline]
68    pub const fn as_ptr(&self) -> Option<NonNull<T>> {
69        self.ptr
70    }
71
72    #[inline]
73    pub fn as_ref<'a>(&self) -> Option<&'a T> {
74        self.ptr.as_ref().map(|ptr| unsafe { ptr.as_ref() })
75    }
76
77    #[inline]
78    pub fn as_mut<'a>(&mut self) -> Option<&'a mut T> {
79        self.ptr.as_mut().map(|ptr| unsafe { ptr.as_mut() })
80    }
81}
82
83impl<T: RefCountable> Clone for NiPointer<T> {
84    #[inline]
85    fn clone(&self) -> Self {
86        let mut cloned = Self::new();
87        if let Some(ptr) = self.ptr {
88            cloned.ptr = Some(ptr);
89            cloned.try_attach();
90        }
91        cloned
92    }
93}
94
95impl<T: RefCountable> Drop for NiPointer<T> {
96    #[inline]
97    fn drop(&mut self) {
98        self.try_detach();
99    }
100}
101
102impl<T: RefCountable> PartialEq for NiPointer<T> {
103    #[inline]
104    fn eq(&self, other: &Self) -> bool {
105        self.ptr == other.ptr
106    }
107}
108
109impl<T: RefCountable> Eq for NiPointer<T> {}
110
111impl<T: RefCountable> Hash for NiPointer<T> {
112    #[inline]
113    fn hash<H: Hasher>(&self, state: &mut H) {
114        if let Some(ptr) = self.ptr {
115            ptr.as_ptr().hash(state);
116        }
117    }
118}
119
120impl<T: RefCountable> From<*mut T> for NiPointer<T> {
121    #[inline]
122    fn from(ptr: *mut T) -> Self {
123        Self::from_raw(ptr)
124    }
125}
126
127impl<T: RefCountable> From<Option<NonNull<T>>> for NiPointer<T> {
128    #[inline]
129    fn from(ptr: Option<NonNull<T>>) -> Self {
130        let ret = Self { ptr, _marker: PhantomData };
131        ret.try_attach();
132        ret
133    }
134}
135
136// #[cfg(test)]
137// mod tests {
138//     use super::*;
139//     use core::sync::atomic::{AtomicU32, Ordering};
140
141//     #[derive(Debug, Default)]
142//     struct TestBase {
143//         count: AtomicU32,
144//     }
145
146//     impl RefCountable for TestBase {
147//         #[inline]
148//         fn inc_ref_count(&self) {
149//             self.count.fetch_add(1, Ordering::AcqRel);
150//         }
151
152//         #[inline]
153//         fn dec_ref_count(&mut self) {
154//             if self.count.fetch_sub(1, Ordering::AcqRel) == 1 {};
155//         }
156//     }
157
158//     #[derive(Debug, Default)]
159//     struct TestRefTarget {
160//         __base: TestBase,
161//     }
162
163//     impl RefCountable for TestRefTarget {
164//         #[inline]
165//         fn inc_ref_count(&self) {
166//             self.__base.inc_ref_count();
167//         }
168
169//         #[inline]
170//         fn dec_ref_count(&mut self) {
171//             self.__base.dec_ref_count();
172//         }
173//     }
174
175//     #[derive(Debug, Default)]
176//     struct TestDerived {
177//         __base: TestBase,
178//         ptr: NiPointer<TestRefTarget>,
179//     }
180
181//     #[test]
182//     fn test_ni_pointer() {
183//         let mut item = TestDerived::default();
184//         assert_eq!(item.__base.count.load(Ordering::Acquire), 1);
185//         item.ptr.reset();
186//         assert_eq!(item.__base.count.load(Ordering::Acquire), 0);
187//     }
188// }